]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
overview: Implement startup animation
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Mon, 15 Feb 2021 20:39:14 +0000 (17:39 -0300)
committerMarge Bot <marge-bot@gnome.org>
Tue, 2 Mar 2021 23:14:07 +0000 (23:14 +0000)
The new startup animation consists of rising the Dash from the bottom,
falling the search entry from the ceiling, and going from HIDDEN to
WINDOW_PICKER with an opacity applied.

One little trick from IconGridLayout was added to ControlsManagerLayout,
which is a promises-based wait for allocation. This is required to make
sure that the transformed position of the search entry is valid, which
is only the case right after an allocation.

This animation also ensures that the overview is shown right on startup.

For session modes that do not have an overview, continue using the same
fade + scale animation.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1678>

js/ui/layout.js
js/ui/overview.js
js/ui/overviewControls.js

index f35787a3045ef06fb5ed2b3bf71b3078a2566ffc..70ece6cab8870b2f29ef62ca6cbfac5c212b2c83 100644 (file)
@@ -664,13 +664,18 @@ var LayoutManager = GObject.registerClass({
             this.keyboardBox.hide();
 
             let monitor = this.primaryMonitor;
-            let x = monitor.x + monitor.width / 2.0;
-            let y = monitor.y + monitor.height / 2.0;
 
-            this.uiGroup.set_pivot_point(x / global.screen_width,
-                                         y / global.screen_height);
-            this.uiGroup.scale_x = this.uiGroup.scale_y = 0.75;
-            this.uiGroup.opacity = 0;
+            if (!Main.sessionMode.hasOverview) {
+                const x = monitor.x + monitor.width / 2.0;
+                const y = monitor.y + monitor.height / 2.0;
+
+                this.uiGroup.set_pivot_point(
+                    x / global.screen_width,
+                    y / global.screen_height);
+                this.uiGroup.scale_x = this.uiGroup.scale_y = 0.75;
+                this.uiGroup.opacity = 0;
+            }
+
             global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
 
             await this._updateBackgrounds();
@@ -700,14 +705,19 @@ var LayoutManager = GObject.registerClass({
     }
 
     _startupAnimationSession() {
-        this.uiGroup.ease({
-            scale_x: 1,
-            scale_y: 1,
-            opacity: 255,
-            duration: STARTUP_ANIMATION_TIME,
-            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
-            onComplete: () => this._startupAnimationComplete(),
-        });
+        const onComplete = () => this._startupAnimationComplete();
+        if (Main.sessionMode.hasOverview) {
+            Main.overview.runStartupAnimation(onComplete);
+        } else {
+            this.uiGroup.ease({
+                scale_x: 1,
+                scale_y: 1,
+                opacity: 255,
+                duration: STARTUP_ANIMATION_TIME,
+                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+                onComplete,
+            });
+        }
     }
 
     _startupAnimationComplete() {
index ac1a349da6d47f1ca742a7fb840ae195fdb686bc..209be42030844213e3842468d166a5f0a93a387c 100644 (file)
@@ -107,6 +107,10 @@ class OverviewActor extends St.BoxLayout {
         this._controls.animateFromOverview(callback);
     }
 
+    runStartupAnimation(callback) {
+        this._controls.runStartupAnimation(callback);
+    }
+
     get dash() {
         return this._controls.dash;
     }
@@ -647,6 +651,23 @@ var Overview = class {
         this._show(OverviewControls.ControlsState.APP_GRID);
     }
 
+    runStartupAnimation(callback) {
+        this._shown = true;
+        this._visible = true;
+        this._visibleTarget = true;
+        Main.layoutManager.showOverview();
+        this._syncGrab();
+
+        Meta.disable_unredirect_for_display(global.display);
+
+        this.emit('showing');
+
+        this._overview.runStartupAnimation(() => {
+            this.emit('shown');
+            callback();
+        });
+    }
+
     getShowAppsButton() {
         logError(new Error('Usage of Overview.\'getShowAppsButton\' is deprecated, ' +
             'use \'dash.showAppsButton\' property instead'));
index 4f0abeb281ec7c73faa1b8224ca55ae00a972846..72542b38138ade82c7bbe248ddfa40aea7332381 100644 (file)
@@ -5,6 +5,7 @@ const { Clutter, Gio, GObject, Meta, Shell, St } = imports.gi;
 
 const AppDisplay = imports.ui.appDisplay;
 const Dash = imports.ui.dash;
+const Layout = imports.ui.layout;
 const Main = imports.ui.main;
 const Overview = imports.ui.overview;
 const SearchController = imports.ui.searchController;
@@ -41,6 +42,7 @@ class ControlsManagerLayout extends Clutter.BoxLayout {
         this._dash = dash;
 
         this._cachedWorkspaceBoxes = new Map();
+        this._postAllocationCallbacks = [];
 
         stateAdjustment.connect('notify::value', () => this.layout_changed());
     }
@@ -100,6 +102,14 @@ class ControlsManagerLayout extends Clutter.BoxLayout {
         return appDisplayBox;
     }
 
+    _runPostAllocation() {
+        if (this._postAllocationCallbacks.length === 0)
+            return;
+
+        this._postAllocationCallbacks.forEach(cb => cb());
+        this._postAllocationCallbacks = [];
+    }
+
     vfunc_set_container(container) {
         this._container = container;
         this.hookup_style(container);
@@ -192,6 +202,14 @@ class ControlsManagerLayout extends Clutter.BoxLayout {
         childBox.set_size(width, availableHeight);
 
         this._searchController.allocate(childBox);
+
+        this._runPostAllocation();
+    }
+
+    ensureAllocation() {
+        this.layout_changed();
+        return new Promise(
+            resolve => this._postAllocationCallbacks.push(resolve));
     }
 
     getWorkspacesBoxForState(state) {
@@ -695,6 +713,60 @@ class ControlsManager extends St.Widget {
         this._stateAdjustment.gestureInProgress = false;
     }
 
+    async runStartupAnimation(callback) {
+        this._ignoreShowAppsButtonToggle = true;
+
+        this._searchController.prepareToEnterOverview();
+        this._workspacesDisplay.prepareToEnterOverview();
+
+        this._stateAdjustment.value = ControlsState.HIDDEN;
+        this._stateAdjustment.ease(ControlsState.WINDOW_PICKER, {
+            duration: Overview.ANIMATION_TIME,
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+        });
+
+        this.dash.showAppsButton.checked = false;
+        this._ignoreShowAppsButtonToggle = false;
+
+        // Set the opacity here to avoid a 1-frame flicker
+        this.opacity = 0;
+
+        // We can't run the animation before the first allocation happens
+        await this.layout_manager.ensureAllocation();
+
+        const { STARTUP_ANIMATION_TIME } = Layout;
+
+        // Opacity
+        this.ease({
+            opacity: 255,
+            duration: STARTUP_ANIMATION_TIME,
+            mode: Clutter.AnimationMode.LINEAR,
+        });
+
+        // Search bar falls from the ceiling
+        const { primaryMonitor } = Main.layoutManager;
+        const [, y] = this._searchEntryBin.get_transformed_position();
+        const yOffset = y - primaryMonitor.y;
+
+        this._searchEntryBin.translation_y = -(yOffset + this._searchEntryBin.height);
+        this._searchEntryBin.ease({
+            translation_y: 0,
+            duration: STARTUP_ANIMATION_TIME,
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+        });
+
+        // The Dash rises from the bottom. This is the last animation to finish,
+        // so run the callback there.
+        this.dash.translation_y = this.dash.height;
+        this.dash.ease({
+            translation_y: 0,
+            delay: STARTUP_ANIMATION_TIME,
+            duration: STARTUP_ANIMATION_TIME,
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+            onComplete: () => callback(),
+        });
+    }
+
     get searchEntry() {
         return this._searchEntry;
     }